#ifndef SETTINGS_H
#define SETTINGS_H
#include <iostream>
#include <sstream>
#include <string>
#include <QString>
#include <ctime>
#include <cstdio>
#include <deque>
#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;

class Settings
{
public:
    enum Pattern { NOT_EXISTING, CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };  // 标定板类型
    enum InputType { INVALID, CAMERA, VIDEO_FILE, IMAGE_LIST };                        // 获取图像的方式

    QString m_SettingName;
    Size m_BoardSize;              // The size of the board -> Number of items by width and height
    Pattern m_CalibrationPattern;  // One of the Chessboard, circles, or asymmetric circle pattern
    string m_OutputFileName;       // The name of the file where to write，输出的xml文件，保存的是标定参数
    string m_Input;                // The input -> 输入的图像路径xml文件
    float m_SquareSize;            // The size of a square in your defined unit (point, millimeter,etc).
    int m_NrFrames;                // The number of frames to use from the input for calibration
    float m_AspectRatio;           // The aspect ratio
    int m_Delay;                   // In case of a video input
    bool m_WritePoints;            // Write detected feature points
    bool m_WriteExtrinsics;        // Write extrinsic parameters
    bool m_WriteGrid;              // Write refined 3D target grid points
    bool m_CalibZeroTangentDist;   // Assume zero tangential distortion
    bool m_CalibFixPrincipalPoint; // Fix the principal point at the center
    bool m_FlipVertical;           // Flip the captured images around the horizontal axis
    bool m_ShowUndistorsed;        // Show undistorted images after calibration
    bool m_UseFisheye;             // use fisheye camera model for calibration
    bool m_FixK1;                  // fix K1 distortion coefficient
    bool m_FixK2;                  // fix K2 distortion coefficient
    bool m_FixK3;                  // fix K3 distortion coefficient
    bool m_FixK4;                  // fix K4 distortion coefficient
    bool m_FixK5;                  // fix K5 distortion coefficient

    int m_CameraID;
    vector<string> m_ImageList;
    size_t m_AtImageList;
    VideoCapture m_InputCapture;
    InputType m_InputType;
    bool m_GoodInput;
    int m_Flag;
private:
    string m_PatternToUse;

public:
    Settings();

    /**
     * @brief write，写文件
     * @param fs，xml文件
     */
    void write(FileStorage& fs) const;                        //Write serialization for this class

    /**
     * @brief read，读文件
     * @param node，xml文件元素
     */
    void read(const FileNode& node);                          //Read serialization for this class

    /**
     * @brief validate，判断读取进来的settings文件里的各个属性是否有效
     */
    void validate();

    /**
     * @brief nextImage，获取下一幅图像，相机拍摄或者本地读取
     * @return
     */
    Mat nextImage();

    /**
     * @brief readStringList，从xml文件中读取图像路径并保存到vector中
     * @param filename，图像路径xml文件的路径
     * @param l，图像路径数组
     * @return 读取是否成功
     */
    static bool readStringList(const string& filename, vector<string>& l );

    /**
     * @brief isListOfImages，检查输入的图像列表文件路径是否是xml或yaml或yml类型
     * @param filename，图像列表文件路径
     * @return
     */
    static bool isListOfImages(const string& filename);

    /**
     * @brief getImgList，返回标定图像队列，可以直接载入到imagewindow控件中
     * @return
     */
    deque<Mat> getImgList();
};

/**
 * @brief read，对read函数的重载，想知道重载哪个函数，把下面的代码注释掉编译一下就知道了
 * 报错的位置就是函数重载的位置
 * @param node
 * @param x
 * @param default_value
 */
static inline void read(const FileNode& node, Settings& x, const Settings& default_value = Settings())
{
    if (node.empty())
        x = default_value;
    else
        x.read(node);
}

#endif // SETTINGS_H
